package org.jeecg.modules.activiti.web;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.qixin.unipush.GeTuiPushV2;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricIdentityLink;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.EmptyUtil;
import org.jeecg.modules.activiti.entity.*;
import org.jeecg.modules.activiti.mapper.ActEaTaskMapper;
import org.jeecg.modules.activiti.service.IActZTaskService;
import org.jeecg.modules.activiti.service.IActZVariableService;
import org.jeecg.modules.activiti.service.Impl.ActBusinessServiceImpl;
import org.jeecg.modules.activiti.service.Impl.ActZprocessServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author pmc
 */
@Slf4j
@RestController
@RequestMapping("/actTask")
@Transactional
@Api(tags = "流程-wmf")
public class ActTaskController {

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ManagementService managementService;

    // 流程定义扩展表
    @Autowired
    private ActZprocessServiceImpl actZprocessService;

    // 流程业务扩展表
    @Autowired
    private ActBusinessServiceImpl actBusinessService;

    // 流程变量配置表
    @Autowired
    private IActZVariableService actZVariableService;
    // 待办任务扩展表
    @Autowired
    private IActZTaskService actZTaskService;

    @Autowired
    ISysBaseAPI sysBaseAPI;
    @Autowired
    ActEaTaskMapper actEaTaskMapper;
    // APP消息推送
    @Autowired
    GeTuiPushV2 geTuiPushV2;


    /*删除流程*/
    @AutoLog(value = "撤销流程")
    @ApiOperation(value="撤销流程", notes="撤销流程")
    @RequestMapping(value = "/cancel", method = RequestMethod.POST)
    public Result<Object> cancel(@ApiParam(value = "关联表id" ,required = true) @RequestParam String tableId,
                                 @ApiParam(value = "流程实例id" ,required = true) @RequestParam String procInstId,
                                 @ApiParam(value = "撤销类型-del-cancel" ,required = true) @RequestParam String cancelType,
                                 @ApiParam(value = "撤销理由原因说明" ,required = false) @RequestParam(required = false) String reason){

        if(StrUtil.isBlank(reason)){
            reason = "";
        }
        runtimeService.deleteProcessInstance(procInstId, "canceled-"+reason);
        QueryWrapper<ActBusiness> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("table_id",tableId).eq("proc_inst_id",procInstId);
        if ("del".equals(cancelType)){
            actBusinessService.remove(queryWrapper);
            QueryWrapper<ActZTask> taskQueryWrapper = new QueryWrapper<>();
            taskQueryWrapper.eq("table_id",tableId).eq("proc_inst_id",procInstId);
            actZTaskService.remove(taskQueryWrapper);
        }else{
            queryWrapper.last(" limit 1");
            ActBusiness actBusiness = actBusinessService.getOne(queryWrapper);
            actBusiness.setStatus(ActivitiConstant.STATUS_CANCELED);
            actBusiness.setResult(ActivitiConstant.RESULT_TO_SUBMIT);
            actBusinessService.updateById(actBusiness);
            //修改业务表的流程字段
            actBusinessService.updateBusinessStatus(actBusiness.getTableName(), actBusiness.getTableId(),"0");
        }
        return Result.ok("操作成功");
    }

    // update-begin-Autor: Wengmf date: 2022-02-11 18:57 for: 流程撤回
    /*流程撤回*/
    @AutoLog(value = "流程撤回")
    @ApiOperation(value="流程撤回", notes="流程撤回")
    @RequestMapping(value = "/withdraw", method = RequestMethod.POST)
    public Result<Object> withdraw(@ApiParam(value = "流程实例id" ,required = true) @RequestParam String procInstId,
                                   @ApiParam(value = "待办任务表Id" ,required = true) @RequestParam String actZTaskId,
                                   @ApiParam(value = "当前序号" ,required = true) @RequestParam Integer serial,
                                   @ApiParam(value = "当前已办任务Id" ,required = true) @RequestParam String taskId,
                                   @ApiParam(value = "是否发起人" , defaultValue = "false") @RequestParam Boolean isStarter ){

        // 判断流程是否可撤回
        if (!isStarter){
            // 不是发起人判断下节点是否已审批
            QueryWrapper<ActZTask> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("node_state",1).eq("serial",serial + 1).eq("proc_inst_id",procInstId);
            List<ActZTask> list = actZTaskService.list(queryWrapper);
            if (list.size() > 0){
                return Result.error("下节点已经审批，不能撤回！");
            }
        }
        // 发起人判断流程是否已审批结束
        QueryWrapper<ActBusiness> businessWrapper = new QueryWrapper<>();
        businessWrapper.eq("proc_inst_id",procInstId).last("limit 1");
        ActBusiness actBusiness = actBusinessService.getOne(businessWrapper);
        if (actBusiness == null){
            return Result.error("该流程实例不存在，请检查！");
        }
        if (actBusiness.getStatus() == 2){
            return Result.error("流程已审批结束，不能撤回！");
        }
        // 执行撤回操作
        if (!actZTaskService.withdraw(procInstId, taskId, actZTaskId, isStarter, serial, actBusiness)){
            return Result.error("流程撤回失败，请稍后再试！");
        }

        return Result.ok("操作成功");
    }
    // update-end-Autor: Wengmf date: 2022-02-11 18:57 for: 流程撤回


    // update-begin-Autor: wjb date: 2022-03-10 10:47 for: 列表流程撤回
    /*列表流程撤回*/
    @AutoLog(value = "列表流程撤回")
    @ApiOperation(value="列表流程撤回", notes="列表流程撤回")
    @RequestMapping(value = "/withdrawInList", method = RequestMethod.POST)
    public Result<Object> withdrawInList(@ApiParam(value = "流程实例id" ,required = true) @RequestParam String procInstId,
                                   @ApiParam(value = "业务表id" ,required = true) @RequestParam String tableId){
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        QueryWrapper<ActZTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("owner_id",loginUser.getId()).eq("proc_inst_id",procInstId).eq("table_id",tableId);
        List<ActZTask> list = actZTaskService.list(queryWrapper);
        if(list.size() > 0 ){
            ActZTask actZTask = list.get(0);
            Result<Object> result = this.withdraw(actZTask.getProcInstId(), actZTask.getId(), actZTask.getSerial(), actZTask.getTaskId(), true);
            return result;
        }else{
            return Result.error("找不到对应的代办任务信息!");
        }
    }
    // update-end-Autor: wjb date: 2022-03-10 10:47 for: 列表流程撤回


    /*提交申请 启动流程*/
    @AutoLog(value = "流程-提交申请 启动流程")
    @ApiOperation(value = "流程-提交申请 启动流程", notes = "提交申请 启动流程。")
    @RequestMapping(value = "/apply", method = RequestMethod.POST)
    public Result apply(@ApiParam(value = "组织Id(传费用承担单位)", required = true) String pkOrgId,
                        @ApiParam(value = "申请标题", required = true) String procDeTitle,
                        @ApiParam(value = "数据表主键", required = true) String tableId,
                        @ApiParam(value = "数据表名", required = true) String tableName,
                        @ApiParam(value = "启动类型-add-send", required = true) String sendType,
                        HttpServletRequest request) throws ScriptException , Exception{

        ActBusiness actBusiness = actBusinessService.getOne(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getTableId, tableId).last("limit 1"));
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String msg = "操作成功!";
//        try {
            if (actBusiness == null) {
                // 根据参数：pkOrgId、tableName查找流程定义扩展表
                QueryWrapper<ActZprocess> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("business_table", tableName)
                        .eq("status", 1)
                        .eq("latest", 1)
                        .inSql("id", "SELECT proc_def_id FROM act_z_process_org WHERE pk_org_id='" + pkOrgId + "'").last("limit 1");
                ActZprocess actZprocess = actZprocessService.getOne(queryWrapper);
                if (actZprocess == null) {
                    return Result.error("未找到可发起的流程，请联系管理员！");
                }

                // 等于空新发起， 新增数据 保存至我的申请业务
                actBusiness = new ActBusiness();
                actBusiness.setUserId(sysUser.getId());
                actBusiness.setTableId(tableId);
                actBusiness.setProcDefId(actZprocess.getId()); // 设置流程定义Id
                actBusiness.setProcessKey(actZprocess.getProcessKey()); // 设置流程标识
                actBusiness.setTitle(procDeTitle); // 设置流程标题
                actBusiness.setTableName(tableName);
                actBusinessService.save(actBusiness);
                actBusiness.setAssignees(sysUser.getId()); // 流程发起人，第一节点默认当前登录用户
                actBusiness.setRouteName(actZprocess.getRouteName()); // 设置表单路由
                // 启动一个新流程
                String processInstanceId = actZprocessService.startProcess(actBusiness);
                actBusiness.setProcInstId(processInstanceId);
                actBusiness.setStatus(ActivitiConstant.STATUS_DEALING);
                actBusiness.setResult(ActivitiConstant.RESULT_DEALING);
                actBusiness.setApplyTime(new Date());
                actBusinessService.updateById(actBusiness);

                if ("send".equals(sendType)){
                    //修改业务表的流程字段
                    actBusinessService.updateStatusAndProcInstId(actBusiness.getTableName(), actBusiness.getTableId(), "1", actBusiness.getProcInstId());
                    // 流程提交到下一个节点
                    this.pass(actBusiness.getTaskId(), processInstanceId, "", 0, "", true, false, false,false);
                }else {
                    //修改业务表的流程字段
                    actBusinessService.updateStatusAndProcInstId(actBusiness.getTableName(), actBusiness.getTableId(), "0", actBusiness.getProcInstId());
                }
            } else {
                // 保存之后发起
                if ("send".equals(sendType)){
                    // update-begin-by wujinbiao 2022/3/30 15:42 for 1、获取最新流程 2、判断当前流程是不是最新流程
                    // 1、获取最新流程
                    QueryWrapper<ActZprocess> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("business_table", tableName)
                            .eq("status", 1)
                            .eq("latest", 1)
                            .inSql("id", "SELECT proc_def_id FROM act_z_process_org WHERE pk_org_id='" + pkOrgId + "'").last("limit 1");
                    ActZprocess actZprocess = actZprocessService.getOne(queryWrapper);
                    // 2、 判断是否是最新流程
                    if(actZprocess != null && actBusiness.getProcDefId().equals(actZprocess.getId())){ // 是最新流程
                        // 查询当前用户任务id
                        List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(sysUser.getId()).processInstanceId(actBusiness.getProcInstId()).list();
                        if (tasks.size() > 0) {
                            //修改业务表的流程字段
                            actBusinessService.updateStatusAndProcInstId(actBusiness.getTableName(), actBusiness.getTableId(), "1", actBusiness.getProcInstId());

                            // 流程提交到下一个节点
                            this.pass(tasks.get(0).getId(), actBusiness.getProcInstId(), "", 0, "", true, false, false,false);
                        } else {
                            return Result.error("提交流程出错，未找到当前任务！");
                        }
                        msg = "流程发起成功！";
                    }else{// 不是最新流程
                        this.cancel(tableId,actBusiness.getProcInstId(),"del","");
                        // 启动最新流程
                        ActBusiness newActBusiness = new ActBusiness();
                        newActBusiness.setUserId(sysUser.getId());
                        newActBusiness.setTableId(tableId);
                        newActBusiness.setProcDefId(actZprocess.getId()); // 设置流程定义Id
                        newActBusiness.setProcessKey(actZprocess.getProcessKey()); // 设置流程标识
                        newActBusiness.setTitle(procDeTitle); // 设置流程标题
                        newActBusiness.setTableName(tableName);
                        actBusinessService.save(newActBusiness);
                        newActBusiness.setAssignees(sysUser.getId()); // 流程发起人，第一节点默认当前登录用户
                        newActBusiness.setRouteName(actZprocess.getRouteName()); // 设置表单路由
                        // 启动一个新流程
                        String processInstanceId = actZprocessService.startProcess(newActBusiness);
                        newActBusiness.setProcInstId(processInstanceId);
                        newActBusiness.setStatus(ActivitiConstant.STATUS_DEALING);
                        newActBusiness.setResult(ActivitiConstant.RESULT_DEALING);
                        newActBusiness.setApplyTime(new Date());
                        newActBusiness.setId(actBusiness.getId());
                        actBusinessService.updateById(newActBusiness);

                        // 查询当前用户任务id
                        List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(sysUser.getId()).processInstanceId(newActBusiness.getProcInstId()).list();
                        if (tasks.size() > 0) {
                            //修改业务表的流程字段
                            actBusinessService.updateStatusAndProcInstId(newActBusiness.getTableName(), newActBusiness.getTableId(), "1", newActBusiness.getProcInstId());

                            // 流程提交到下一个节点
                            this.pass(tasks.get(0).getId(), newActBusiness.getProcInstId(), "", 0, "", true, false, false,false);
                        } else {
                            return Result.error("提交流程出错，未找到当前任务！");
                        }
                        msg = "流程发起成功！";

                    }
                    // update-end-by wujinbiao 2022/3/30 15:42 for 1、获取最新流程 2、判断当前流程是不是最新流程

                }
            }
//        } catch (ScriptException e) {
//            e.printStackTrace();
//            return Result.error("提交流程出现异常，错误信息为：" + e.getMessage());
//        } catch (Exception ex){
//            ex.printStackTrace();
//            return Result.error("提交流程出现异常，错误信息为：" + ex.getMessage());
//        }
        Map<String, String> map = new HashMap<>();
        map.put("procInstId",actBusiness.getProcInstId());
        return Result.OK(msg,map);
    }

    @RequestMapping(value = "/pass", method = RequestMethod.POST)
    @AutoLog(value = "流程-任务节点审批通过")
    @ApiOperation(value = "任务节点审批通过")
    public Result<Object> pass(@ApiParam("任务id") @RequestParam String id,
                               @ApiParam("流程实例id") @RequestParam String procInstId,
                               @ApiParam("节点自动审批人id") @RequestParam(required = false) String nextUserId,
                               @ApiParam("优先级") @RequestParam(required = false) Integer priority,
                               @ApiParam("意见评论") @RequestParam(required = false) String comment,
                               @ApiParam("是否发送站内消息") @RequestParam(defaultValue = "false") Boolean sendMessage,
                               @ApiParam("是否发送短信通知") @RequestParam(defaultValue = "false") Boolean sendSms,
                               @ApiParam("是否发送邮件通知") @RequestParam(defaultValue = "false") Boolean sendEmail,
                               @ApiParam("是否驳回") @RequestParam(defaultValue = "false") Boolean isBack) throws ScriptException, Exception {

        if (StrUtil.isBlank(comment)) {
            comment = "";
        }
        taskService.addComment(id, procInstId, comment);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId).singleResult();
        Task task = taskService.createTaskQuery().taskId(id).singleResult();
        if (StrUtil.isNotBlank(task.getOwner()) && !("RESOLVED").equals(task.getDelegationState().toString())) {
            // 未解决的委托任务 先resolve
            String oldAssignee = task.getAssignee();
            taskService.resolveTask(id);
            taskService.setAssignee(id, oldAssignee);
        }

        /**
         * 获取流程变量 -- 设置流程变量
         * 设置流程变量
         * 表单字段可当为流程变量
         */
        ActBusiness actBusiness = actBusinessService.getById(pi.getBusinessKey());

        // update-begin-Autor: Wengmf date: 2022-01-14 11:42 for: 获取流程变量，设置流程变量 流程变量命名规则：驼峰表达式
        QueryWrapper<ActZVariable> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("process_key", actBusiness.getProcessKey()).eq("process_node", task.getName());
        List<ActZVariable> zVariableList = actZVariableService.list(queryWrapper);
        // 获取表单数据
        Map<String, Object> busiData = actBusinessService.getBusiData(actBusiness.getTableId(), actBusiness.getTableName());
        if (zVariableList.size() > 0) {
            for (ActZVariable zVariable : zVariableList) {
                if (zVariable.getVarType() == 1 && StringUtils.isNotBlank(zVariable.getVarValue())) {
                    // JS脚本 -- 解析JS代码块
                    ScriptEngineManager manager = new ScriptEngineManager();
                    ScriptEngine engine = manager.getEngineByName("js");
                    String jsString = zVariable.getVarValue().replaceAll("or", "||");
                    jsString = jsString.replaceAll("and", "&&");
                    engine.put(zVariable.getVarName(), busiData.get(zVariable.getVarName()));
                    Object result = engine.eval(jsString);

                    taskService.setVariable(id, zVariable.getVarName(), result);
                } else {
                    // 表单值
                    taskService.setVariable(id, zVariable.getVarName(), busiData.get(zVariable.getVarName()));
                }
            }
        }
        // 设置审批通过
        int taskState = 1; // 同意
        if (isBack){
            // 驳回
            taskService.setVariable(id, "audit", 2);
            taskState = 3; // 驳回
        }else{
            taskService.setVariable(id, "audit", 1);
        }

        // update-end-Autor: Wengmf date: 2022-01-14 11:42 for: 获取流程变量，设置流程变量

        /*会签思路：
        act_hi_identitylink记录着审批历史 ActivitiConstant.EXECUTOR_TYPE_p 标识审批通过
        1、节点设置中增加人数字段，表示需要多少人通过这个任务节点才通过
        2、此处查询审批历史，查看当前节点的审批情况，符合预设的人数调用 taskService.complete(id); 完成该节点任务
        否则只记录审批数据，不完成该任务节点
        3、会有的问题：
            1、如此，审批过的人代办中还会看到这条任务，需要标识自己审批过，但是这条任务自己不能再审了  或 能再审，但是再审记得把之前审批过的记录删掉
            2、下一个节点的审批人只能最后通过的人选择才有效
            3、如果下一个节点是会签，指定下一节点的审批人的数量必须不小于节点预设数量
            其他问题，待暴露
          */

        /*完成任务*/
        taskService.complete(id);

        LoginUser loginUser = null;

        if (StringUtils.isBlank(nextUserId)){
            loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        }else{
            loginUser = sysBaseAPI.getUserById(nextUserId);
        }

        // update-begin-Autor: Wengmf date: 2022-02-09 1:12 for: 获取当前任务信息
        QueryWrapper<ActZTask> taskQueryWrapper = new QueryWrapper<>();
        taskQueryWrapper.eq("owner_id",loginUser.getId())
                .eq("task_id",id)
                .eq("proc_inst_id",procInstId)
                .last(" limit 1");
        ActZTask oldTask = actZTaskService.getOne(taskQueryWrapper);
        // update-begin-by wujinbiao 2022/2/28 15:28 for 完成当前节点任务，多人审批只需一个人通过，同一节点其他审批人自动通过
        //完成当前节点任务
        actZTaskService.updateState(oldTask.getId(),taskState,1, comment);
//         actZTaskService.updateState(oldTask.getId(),taskState,1, comment);


        // update-end-by wujinbiao 2022/2/28 15:28 for 完成当前节点任务，多人审批只需一个人通过，同一节点其他审批人自动通过


        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procInstId).list();
        // 判断下一个节点
        if (tasks != null && tasks.size() > 0) {
            // 记录下节点审批人Id
            List<String> nextUserIds = new ArrayList<>();
            for (Task t : tasks) {
//                if (StrUtil.isBlank(assignees)) {
                    // 获取下节点审批人 make
//                    List<LoginUser> users = actZprocessService.getNode(t.getTaskDefinitionKey(), actBusiness.getTableName(), actBusiness.getTableId(), actBusiness.getProcDefId()).getUsers();
                    List<LoginUser> users = actZprocessService.getNode(t.getTaskDefinitionKey(), actBusiness.getProcDefId(), busiData).getUsers();

                    // 如果下个节点未分配审批人为空 抛出异常
                    if (users == null || users.size() == 0) {
                        // update-begin-Autor: Wengmf date: 2022-02-10 19:12 for: 下级节点未分配审批人，请设置
                        throw new RuntimeException("下级节点未分配审批人，请设置");
                        // update-begin-Autor: Wengmf date: 2022-02-10 19:12 for: 下级节点未分配审批人，请设置

                    } else {
                        // 避免重复添加
                        List<String> list = actBusinessService.selectIRunIdentity(t.getId(), ActivitiConstant.EXECUTOR_candidate);
                        if (list == null || list.size() == 0) {
                            // 分配了节点负责人分发给全部
                            for (LoginUser user : users) {
                                //添加下节点审批人
                                taskService.addCandidateUser(t.getId(), user.getId());
                                // 记录下节点审批人-- 自动完成任务用到
                                nextUserIds.add(user.getId());
                                // update-begin-Autor: Wengmf date: 2022-02-09 1:18 for: 添加自定义待办任务
                                ActZTask actZTask = new ActZTask();
                                BeanUtils.copyProperties(oldTask,actZTask);
                                actZTask.setId(null); // Id设为空表示新增
                                actZTask.setCreateTime(new Date()); // 创建时间
                                actZTask.setOwnerId(user.getId());//审批人id
                                actZTask.setOwnerName(user.getRealname()); //审批人名称
                                actZTask.setAuditTime(null);//审批时间
                                actZTask.setAuditComment(null);//审批意见
                                actZTask.setReceiveTime(actZTask.getCreateTime()); // 接收时间
                                actZTask.setNodeName(t.getName()); //任务节点名称
                                actZTask.setNodeState(0);//节点状态：0未处理1已处理
                                actZTask.setTaskId(t.getId()); //工作流任务id
                                actZTask.setSerial(oldTask.getSerial() + 1);//序号
                                actZTask.setState(1);//流程状态 0待提交 1审批中 2审批结束 3 驳回
                                if (isBack){
                                    actZTask.setState(3);//流程状态 0待提交 1审批中 2审批结束 3 驳回
                                }
                                actZTaskService.save(actZTask);
                                // update-end-Autor: Wengmf date: 2022-02-09 1:18 for: 添加自定义待办任务

                                // 异步发消息
                                actZprocessService.sendActMessage(loginUser, user, actBusiness, t.getName(), sendMessage, sendSms, sendEmail);
                                // 异步发APP消息
                                String msgTitle = "您有一个新的审批任务：" + actBusiness.getTitle();
                                String content = "当前节点：" + t.getName() + "，请进入待办栏，尽快处理！";
                                geTuiPushV2.pushToSingleByCid(user, msgTitle, content);
                            }
                            taskService.setPriority(t.getId(), task.getPriority());
                        }
                    }
            /*    } else {
                    // 避免重复添加
                    List<String> list = actBusinessService.selectIRunIdentity(t.getId(), ActivitiConstant.EXECUTOR_candidate);
                    if (list == null || list.size() == 0) {
                        for (String assignee : assignees.split(",")) {
                            taskService.addCandidateUser(t.getId(), assignee);
                            // 异步发消息
                            LoginUser user = sysBaseAPI.getUserByName(assignee);
                            actZprocessService.sendActMessage(loginUser, user, actBusiness, task.getName(), sendMessage, sendSms, sendEmail);
                            taskService.setPriority(t.getId(), priority);
                        }
                    }
                }
            */
            }
            // update-begin-Autor: Wengmf date: 2022-02-10 19:12 for: 驳回时,把审核通过改为驳回，前端流程审批记录用到

            // 记录实际审批人员
            actBusinessService.insertHI_IDENTITYLINK(IdUtil.simpleUUID(),
                    ActivitiConstant.EXECUTOR_TYPE_p, loginUser.getId(), id, procInstId);

            if(isBack){
                //驳回时,将流程历史中的delete_reason改成backed
                actZprocessService.updateTaskBack(id);
                //修改业务表的流程字段 -- 驳回
                actBusinessService.updateBusinessStatus(actBusiness.getTableName(), actBusiness.getTableId(), "3");
                // 流程流转驳回
                actBusiness.setStatus(ActivitiConstant.STATUS_CANCELED);
                actBusiness.setResult(ActivitiConstant.RESULT_FAIL);
                actBusinessService.updateById(actBusiness);
                //更新待办任务表流程状态-- 驳回
                actZTaskService.updateActZTaskState(3, procInstId);
            }else{
                //修改业务表的流程字段
                actBusinessService.updateBusinessStatus(actBusiness.getTableName(), actBusiness.getTableId(), "1");

                // update-begin-Autor: Wengmf date: 2022-02-12 20:50 for: 判断下节点的审批人前面已经审批过了，如有自动完成任务
                QueryWrapper<ActZTask> zTaskWrapper = new QueryWrapper<>();
                zTaskWrapper.eq("proc_inst_id",procInstId).eq("node_state",1).eq("state",1)
                        .in("owner_id",nextUserIds).last("limit 1");
                ActZTask nextTask = actZTaskService.getOne(zTaskWrapper);
                if (nextTask != null){
                    this.pass(tasks.get(0).getId(), procInstId, nextTask.getOwnerId(), 0, "同意", true, false, false,false);

                }
                // update-end-Autor: Wengmf date: 2022-02-12 20:50 for: 判断下节点的审批人前面已经审批过了，如有自动完成任务


            }
            // update-end-Autor: Wengmf date: 2022-02-10 19:12 for: 驳回时,把审核通过改为驳回，前端流程审批记录用到

        } else {
            // 流程流转结束
            actBusiness.setStatus(ActivitiConstant.STATUS_FINISH);
            actBusiness.setResult(ActivitiConstant.RESULT_PASS);
            actBusinessService.updateById(actBusiness);
            // 异步发消息
            LoginUser user = sysBaseAPI.getUserById(actBusiness.getUserId());
            actZprocessService.sendMessage(actBusiness.getId(), loginUser, user, ActivitiConstant.MESSAGE_PASS_CONTENT,
                    String.format("您的 【%s】 申请已通过！", actBusiness.getTitle()), sendMessage, sendSms, sendEmail);
            //修改业务表的流程字段 -- 流程审批结束
            actBusinessService.updateBusinessStatus(actBusiness.getTableName(), actBusiness.getTableId(), "2");
            //完成当前节点任务
            actZTaskService.updateState(oldTask.getId(),2,1, comment);
            //更新待办任务表流程状态 -- 审批通过
            actZTaskService.updateActZTaskState(2, procInstId);

            // 记录实际审批人员
            actBusinessService.insertHI_IDENTITYLINK(IdUtil.simpleUUID(),
                    ActivitiConstant.EXECUTOR_TYPE_p, loginUser.getId(), id, procInstId);

            // 异步发APP消息
            geTuiPushV2.pushToSingleByCid(user, ActivitiConstant.MESSAGE_PASS_CONTENT, String.format("您的 【%s】 申请已通过！", actBusiness.getTitle()));

        }

        return Result.ok("操作成功");
    }

    /*流程流转历史*/
    @AutoLog(value = "流程-流程流转历史")
    @ApiOperation(value = "流程-流程流转历史", notes = "流程流转历史")
    @RequestMapping(value = "/historicFlow/{id}", method = RequestMethod.GET)
    public Result<Object> historicFlow(@ApiParam("实例Id") @PathVariable String id) {

        List<HistoricTaskVo> list = new ArrayList<>();

        List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(id).orderByHistoricTaskInstanceEndTime().asc().list();

        // 转换vo
        taskList.forEach(e -> {
            HistoricTaskVo htv = new HistoricTaskVo(e);
            List<Assignee> assignees = new ArrayList<>();
            // 关联分配人（委托用户时显示该人）
            if (StrUtil.isNotBlank(htv.getAssignee())) {
                String assignee = sysBaseAPI.getUserById(htv.getAssignee()).getRealname();
                String owner = sysBaseAPI.getUserById(htv.getOwner()).getRealname();
                assignees.add(new Assignee(assignee + "(受" + owner + "委托)", true));
            }
            List<HistoricIdentityLink> identityLinks = historyService.getHistoricIdentityLinksForTask(e.getId());
            // 获取实际审批用户id
            List<String> userIds_b = actBusinessService.findUserIdByTypeAndTaskId(ActivitiConstant.EXECUTOR_TYPE_b, e.getId());
            List<String> userIds_p = actBusinessService.findUserIdByTypeAndTaskId(ActivitiConstant.EXECUTOR_TYPE_p, e.getId());
            for (HistoricIdentityLink hik : identityLinks) {
                // 关联候选用户（分配的候选用户审批人）
                if (ActivitiConstant.EXECUTOR_candidate.equals(hik.getType()) && StrUtil.isNotBlank(hik.getUserId())) {
                    String username = sysBaseAPI.getUserById(hik.getUserId()).getRealname();
                    Assignee assignee = new Assignee(username, false);
                    /*审批过的标记一下，前端标颜色用*/
                    if (CollectionUtil.contains(userIds_b, hik.getUserId()) || CollectionUtil.contains(userIds_p, hik.getUserId())) {
                        assignee.setIsExecutor(true);
                    }
                    assignees.add(assignee);
                }
            }
            htv.setAssignees(assignees);
            // 关联审批意见
            List<Comment> comments = taskService.getTaskComments(htv.getId(), "comment");
            if (comments != null && comments.size() > 0) {
                htv.setComment(comments.get(0).getFullMessage());
            }

            //如果deletereason为审批通过,同时
            String deleteReason = EmptyUtil.checkNull(htv.getDeleteReason());
            String name = EmptyUtil.checkNull(htv.getName());
            if (name.equals("用户提交") && deleteReason.equals("审批通过")) {
                htv.setDeleteReason("提交审批");
            }

            list.add(htv);
        });
        return Result.ok(list);
    }

    @RequestMapping(value = "/delegate", method = RequestMethod.POST)
    @ApiOperation(value = "委托他人代办")
    @AutoLog(value = "流程-委托他人代办")
    public Result<Object> delegate(@ApiParam("任务id") @RequestParam String id,
                                   @ApiParam("委托用户id") @RequestParam String userId,
                                   @ApiParam("流程实例id") @RequestParam String procInstId,
                                   @ApiParam("意见评论") @RequestParam(required = false) String comment,
                                   @ApiParam("是否发送站内消息") @RequestParam(defaultValue = "false") Boolean sendMessage,
                                   @ApiParam("是否发送短信通知") @RequestParam(defaultValue = "false") Boolean sendSms,
                                   @ApiParam("是否发送邮件通知") @RequestParam(defaultValue = "false") Boolean sendEmail) {

        if (StrUtil.isBlank(comment)) {
            comment = "";
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        //设置审核通过状态
        taskService.setVariable(id, "audit", "2");

        LoginUser loginUser = sysBaseAPI.getUserByName(userId);

        taskService.addComment(id, procInstId, comment);
        taskService.delegateTask(id, loginUser.getId());
        taskService.setOwner(id, sysUser.getId());
        ActBusiness actBusiness = actBusinessService.getOne(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getProcInstId, procInstId).last("limit 1"));
        // 异步发消息
        actZprocessService.sendMessage(actBusiness.getId(), sysUser, loginUser, ActivitiConstant.MESSAGE_DELEGATE_CONTENT,
                String.format("您有一个来自 %s 的委托需要处理！", sysUser.getRealname()), sendMessage, sendSms, sendEmail);
        return Result.ok("操作成功");
    }

    @RequestMapping(value = "/backToTask", method = RequestMethod.POST)
    @ApiOperation(value = "任务节点审批驳回至指定历史节点")
    @AutoLog(value = "流程-任务节点审批驳回至指定历史节点")
    public Result<Object> backToTask(@ApiParam("任务id") @RequestParam String id,
                                     @ApiParam("驳回指定节点key") @RequestParam String backTaskKey,
                                     @ApiParam("流程实例id") @RequestParam String procInstId,
                                     @ApiParam("流程定义id") @RequestParam String procDefId,
                                     @ApiParam("原节点审批人") @RequestParam(required = false) String assignees,
                                     @ApiParam("优先级") @RequestParam(required = false) Integer priority,
                                     @ApiParam("意见评论") @RequestParam(required = false) String comment,
                                     @ApiParam("是否发送站内消息") @RequestParam(defaultValue = "false") Boolean sendMessage,
                                     @ApiParam("是否发送短信通知") @RequestParam(defaultValue = "false") Boolean sendSms,
                                     @ApiParam("是否发送邮件通知") @RequestParam(defaultValue = "false") Boolean sendEmail) {


        if (StrUtil.isBlank(comment)) {
            comment = "";
        }
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        taskService.addComment(id, procInstId, comment);
        // 取得流程定义
        ProcessDefinitionEntity definition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(procDefId);
        // 获取历史任务的Activity
        ActivityImpl hisActivity = definition.findActivity(backTaskKey);
        // 实现跳转
        managementService.executeCommand(new JumpTask(procInstId, hisActivity.getId()));
        // 重新分配原节点审批人
        ActBusiness actBusiness = actBusinessService.getOne(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getProcInstId, procInstId).last("limit 1"));
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procInstId).list();
        if (tasks != null && tasks.size() > 0) {
            tasks.forEach(e -> {
                for (String assignee : assignees.split(",")) {
                    taskService.addCandidateUser(e.getId(), assignee);
                    // 异步发消息
                    actZprocessService.sendMessage(actBusiness.getId(), loginUser, sysBaseAPI.getUserById(assignee), ActivitiConstant.MESSAGE_TODO_CONTENT
                            , "您有一个任务待审批，请尽快处理！", sendMessage, sendSms, sendEmail);
                }
                if (priority != null) {
                    taskService.setPriority(e.getId(), priority);
                }
            });
        }
        // 记录实际审批人员
        actBusinessService.insertHI_IDENTITYLINK(IdUtil.simpleUUID(),
                ActivitiConstant.EXECUTOR_TYPE_b, loginUser.getId(), id, procInstId);
        return Result.ok("操作成功");
    }

    public class JumpTask implements Command<ExecutionEntity> {

        private String procInstId;
        private String activityId;

        public JumpTask(String procInstId, String activityId) {
            this.procInstId = procInstId;
            this.activityId = activityId;
        }

        @Override
        public ExecutionEntity execute(CommandContext commandContext) {

            ExecutionEntity executionEntity = commandContext.getExecutionEntityManager().findExecutionById(procInstId);
            executionEntity.destroyScope("backed");
            ProcessDefinitionImpl processDefinition = executionEntity.getProcessDefinition();
            ActivityImpl activity = processDefinition.findActivity(activityId);
            executionEntity.executeActivity(activity);

            return executionEntity;
        }

    }

    /*已办列表*/
    @AutoLog(value = "流程-已办列表")
    @ApiOperation(value = "流程-已办列表", notes = "已办列表")
    @RequestMapping(value = "/doneList", method = RequestMethod.GET)
    public Result<Object> doneList(String name,
                                   String categoryId,
                                   Integer priority,
                                   HttpServletRequest req) {

        List<HistoricTaskVo> list = actBusinessService.getHistoricTaskVos(req, name, categoryId, priority);
        return Result.ok(list);
    }

    /*删除任务历史*/
    @AutoLog(value = "流程-删除任务历史")
    @ApiOperation(value = "流程-删除任务历史", notes = "删除任务历史")
    @RequestMapping(value = "/deleteHistoric/{ids}", method = RequestMethod.POST)
    public Result<Object> deleteHistoric(@PathVariable String ids) {

        for (String id : ids.split(",")) {
            historyService.deleteHistoricTaskInstance(id);
        }
        return Result.ok("操作成功");
    }

    /*流程流转历史-formId*/
    @AutoLog(value = "流程-流程流转历史-formId")
    @ApiOperation(value = "流程-流程流转历史-formId", notes = "流程流转历史-formId")
    @RequestMapping(value = "/historicFlowByFormId", method = RequestMethod.POST)
    public Result<Object> historicFlowByFormId(@RequestBody IdVo idVo) {
        String formId = idVo.getId();   //单据id
        Map params = new HashMap();
        params.put("form_id", formId);
        List<ActEaTask> eaTasks = actEaTaskMapper.selectByMap(params);   //任务表,获取procInstId

        List<HistoricTaskVo> list = new ArrayList<>();

        String procInstId = EmptyUtil.checkNull(eaTasks.get(0).getProcinstId());   //流程id
        if (procInstId.equals("")) {
            return Result.error("流程id为空");
        }

        List<HistoricTaskInstance> taskList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(procInstId).orderByHistoricTaskInstanceEndTime().asc().list();

        // 转换vo
        taskList.forEach(e -> {
            HistoricTaskVo htv = new HistoricTaskVo(e);
            List<Assignee> assignees = new ArrayList<>();
            // 关联分配人（委托用户时显示该人）
            if (StrUtil.isNotBlank(htv.getAssignee())) {
                String assignee = sysBaseAPI.getUserById(htv.getAssignee()).getRealname();
                String owner = sysBaseAPI.getUserById(htv.getOwner()).getRealname();
                assignees.add(new Assignee(assignee + "(受" + owner + "委托)", true));
            }
            List<HistoricIdentityLink> identityLinks = historyService.getHistoricIdentityLinksForTask(e.getId());
            // 获取实际审批用户id
            List<String> userIds_b = actBusinessService.findUserIdByTypeAndTaskId(ActivitiConstant.EXECUTOR_TYPE_b, e.getId());
            List<String> userIds_p = actBusinessService.findUserIdByTypeAndTaskId(ActivitiConstant.EXECUTOR_TYPE_p, e.getId());
            for (HistoricIdentityLink hik : identityLinks) {
                // 关联候选用户（分配的候选用户审批人）
                if (ActivitiConstant.EXECUTOR_candidate.equals(hik.getType()) && StrUtil.isNotBlank(hik.getUserId())) {
                    String username = sysBaseAPI.getUserById(hik.getUserId()).getRealname();
                    Assignee assignee = new Assignee(username, false);
                    /*审批过的标记一下，前端标颜色用*/
                    if (CollectionUtil.contains(userIds_b, hik.getUserId()) || CollectionUtil.contains(userIds_p, hik.getUserId())) {
                        assignee.setIsExecutor(true);
                    }
                    assignees.add(assignee);
                }
            }
            htv.setAssignees(assignees);
            // 关联审批意见
            List<Comment> comments = taskService.getTaskComments(htv.getId(), "comment");
            if (comments != null && comments.size() > 0) {
                htv.setComment(comments.get(0).getFullMessage());
            }

            //如果deletereason为审批通过,同时
            String deleteReason = EmptyUtil.checkNull(htv.getDeleteReason());
            String name = EmptyUtil.checkNull(htv.getName());
            if (name.equals("用户提交") && deleteReason.equals("审批通过")) {
                htv.setDeleteReason("提交审批");
            }

            list.add(htv);
        });
        return Result.ok(list);
    }

    /*待办列表*/
    @AutoLog(value = "流程-待办列表")
    @ApiOperation(value = "流程-待办列表", notes = "待办列表")
    @RequestMapping(value = "/todoList", method = RequestMethod.GET)
    public Result<Object> todoList(@ApiParam(value = "任务名称") String name,
                                   @ApiParam(value = "任务分类") String categoryId,
                                   @ApiParam(value = "优先级") Integer priority,
                                   @ApiParam(value = "创建开始时间") String createTime_begin,
                                   @ApiParam(value = "创建结束时间") String createTime_end,
                                   HttpServletRequest request) {
        List<TaskVo> list = new ArrayList<>();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = sysUser.getId();
        TaskQuery query = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
        // 多条件搜索
        query.orderByTaskPriority().desc();
        query.orderByTaskCreateTime().desc();
        if (StrUtil.isNotBlank(name)) {
            query.taskNameLike("%" + name + "%");
        }
        if (StrUtil.isNotBlank(categoryId)) {
            query.taskCategory(categoryId);
        }
        if (priority != null) {
            query.taskPriority(priority);
        }
        if (StrUtil.isNotBlank(createTime_begin)) {
            Date start = DateUtil.parse(createTime_begin);
            query.taskCreatedAfter(start);
        }
        if (StrUtil.isNotBlank(createTime_end)) {
            Date end = DateUtil.parse(createTime_end);
            query.taskCreatedBefore(DateUtil.endOfDay(end));
        }
        //流程类型
        String type = request.getParameter("type");
        String proDefId = request.getParameter("proDefId");
        if (StringUtils.isNotEmpty(proDefId)) {
            query.processDefinitionId(proDefId);
        } else if (StrUtil.isNotBlank(type)) {
            List<String> deployment_idList = actBusinessService.getBaseMapper().deployment_idListByType(type);
            if (deployment_idList.size() == 0) {
                query.deploymentIdIn(Lists.newArrayList(""));
            } else {
                query.deploymentIdIn(deployment_idList);
            }
        }
        String searchVal = request.getParameter("searchVal");
        if (StrUtil.isNotBlank(searchVal)) {
            //搜索标题、申请人
            List<LoginUser> usersByName = actBusinessService.getBaseMapper().getUsersByName(searchVal);
            List<String> uNames = null;
            if (usersByName.size() == 0) {
                uNames = Lists.newArrayList("");
            } else {
                uNames = usersByName.stream().map(u -> u.getUsername()).collect(Collectors.toList());
            }
            List<ActBusiness> businessList = actBusinessService.list(new LambdaQueryWrapper<ActBusiness>()
                    .like(ActBusiness::getTitle, searchVal) //标题查询
                    .or().in(ActBusiness::getUserId, uNames)
            );
            if (businessList.size() > 0) {
                // 定义id
                List<String> pids = businessList.stream().filter(act -> act.getProcInstId() != null).map(act -> act.getProcInstId()).collect(Collectors.toList());
                query.processInstanceIdIn(pids);
            } else {
                query.processInstanceIdIn(Lists.newArrayList(""));
            }
        }
        List<Task> taskList = query.list();
        // 是否需要业务数据
        String needData = request.getParameter("needData");
        // 转换vo
        taskList.forEach(e -> {
            TaskVo tv = new TaskVo(e);

            // 关联委托人
            if (StrUtil.isNotBlank(tv.getOwner())) {
                String realname = sysBaseAPI.getUserById(tv.getOwner()).getRealname();
                tv.setOwner(realname);
            }
            List<IdentityLink> identityLinks = runtimeService.getIdentityLinksForProcessInstance(tv.getProcInstId());
            for (IdentityLink ik : identityLinks) {
                // 关联发起人
                if ("starter".equals(ik.getType()) && StrUtil.isNotBlank(ik.getUserId())) {
                    String a = sysBaseAPI.getUserById(ik.getUserId()).getRealname();
                    tv.setApplyer(a);
                }
            }
            // 关联流程信息
            ActZprocess actProcess = actZprocessService.getById(tv.getProcDefId());
            if (actProcess != null) {
                tv.setProcessName(actProcess.getName());
                tv.setRouteName(actProcess.getRouteName());
            }
            // 关联业务key
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(tv.getProcInstId()).singleResult();
            tv.setBusinessKey(pi.getBusinessKey());
            ActBusiness actBusiness = actBusinessService.getById(pi.getBusinessKey());
            if (actBusiness != null) {
                tv.setTableId(actBusiness.getTableId());
                tv.setTableName(actBusiness.getTableName());
                tv.setTitle(actBusiness.getTitle());
                tv.setStatus(actBusiness.getStatus());
                tv.setResult(actBusiness.getResult());
                if (StrUtil.equals(needData, "true")) { // 需要业务数据
                    Map<String, Object> applyForm = actBusinessService.getApplyForm(actBusiness.getTableId(), actBusiness.getTableName());
                    tv.setDataMap(applyForm);
                }
            }
            list.add(tv);
        });
        return Result.ok(list);
    }

    /*查询当前登陆人的待办数量*/
    @AutoLog(value = "流程-待办条数")
    @ApiOperation(value = "流程-待办条数", notes = "待办列表")
    @RequestMapping(value = "/todoCounts", method = RequestMethod.GET)
    public Result<Object> todoList(@ApiParam(value = "流程定义key") @RequestParam(value = "procDefIds", defaultValue = "") String procDefIds,
                                   HttpServletRequest request) {
        Map<String, Integer> todoCounts = new HashMap<>();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = sysUser.getId();
        TaskQuery query = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
        if (procDefIds.length() == 0) {
            List<Task> list = query.list();
            for (Task task : list) {
                Integer count = todoCounts.get(task.getProcessDefinitionId());
                if (count == null) {
                    todoCounts.put(task.getProcessDefinitionId(), Integer.valueOf(1));
                } else {
                    todoCounts.put(task.getProcessDefinitionId(), ++count);
                }
            }
        } else {
            String array[] = procDefIds.split(",");
            for (String procDefId : array) {
                List<Task> list = query.processDefinitionId(procDefId).list();
                todoCounts.put(procDefId, Integer.valueOf(0));
                if (list.size() > 0) {
                    todoCounts.put(procDefId, Integer.valueOf(list.size()));
                }
            }
        }

        return Result.ok(todoCounts);
    }

    /*获取可返回的节点*/
    @AutoLog(value = "流程-获取可返回的节点")
    @ApiOperation(value = "流程-获取可返回的节点", notes = "获取可返回的节点")
    @RequestMapping(value = "/getBackList/{procInstId}", method = RequestMethod.GET)
    public Result<Object> getBackList(@PathVariable String procInstId) {

        List<HistoricTaskVo> list = new ArrayList<>();
        List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(procInstId)
                .finished().list();

        taskInstanceList.forEach(e -> {
            HistoricTaskVo htv = new HistoricTaskVo(e);
            list.add(htv);
        });

        // 去重
        LinkedHashSet<String> set = new LinkedHashSet<String>(list.size());
        List<HistoricTaskVo> newList = new ArrayList<>();
        list.forEach(e -> {
            if (set.add(e.getName())) {
                newList.add(e);
            }
        });

        return Result.ok(newList);
    }

    /*任务节点审批 驳回至发起人*/
    @AutoLog(value = "流程-任务节点审批 驳回至发起人")
    @ApiOperation(value = "流程-任务节点审批 驳回至发起人", notes = "任务节点审批 驳回至发起人")
    @RequestMapping(value = "/back", method = RequestMethod.POST)
    public Result<Object> back(@ApiParam("任务id") @RequestParam String id,
                               @ApiParam("流程实例id") @RequestParam String procInstId,
                               @ApiParam("意见评论") @RequestParam(required = false) String comment,
                               @ApiParam("是否发送站内消息") @RequestParam(defaultValue = "false") Boolean sendMessage,
                               @ApiParam("是否发送短信通知") @RequestParam(defaultValue = "false") Boolean sendSms,
                               @ApiParam("是否发送邮件通知") @RequestParam(defaultValue = "false") Boolean sendEmail) {


        if (StrUtil.isBlank(comment)) {
            comment = "";
        }
        taskService.addComment(id, procInstId, comment);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId).singleResult();
        // 删除流程实例
        runtimeService.deleteProcessInstance(procInstId, "backed");
        ActBusiness actBusiness = actBusinessService.getById(pi.getBusinessKey());
        actBusiness.setStatus(ActivitiConstant.STATUS_FINISH);
        actBusiness.setResult(ActivitiConstant.RESULT_FAIL);
        actBusinessService.updateById(actBusiness);

        // update-begin-Autor: Wengmf date: 2022-02-09 1:12 for: 获取当前任务信息
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        QueryWrapper<ActZTask> taskQueryWrapper = new QueryWrapper<>();
        taskQueryWrapper.eq("owner_id",loginUser.getId())
                .eq("task_id",id)
                .eq("proc_inst_id",procInstId)
                .last(" limit 1");
        ActZTask oldTask = actZTaskService.getOne(taskQueryWrapper);
        //完成当前节点任务
        actZTaskService.updateState(oldTask.getId(),1,1, comment);
        // update-end-Autor: Wengmf date: 2022-02-09 1:12 for: 获取当前任务信息

        // 异步发消息
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        actZprocessService.sendMessage(actBusiness.getId(), sysUser, sysBaseAPI.getUserById(actBusiness.getUserId()), ActivitiConstant.MESSAGE_BACK_CONTENT,
                String.format("您的 【%s】 申请已被驳回！", actBusiness.getTitle()), sendMessage, sendSms, sendEmail);
        // 记录实际审批人员
        actBusinessService.insertHI_IDENTITYLINK(IdUtil.simpleUUID(),
                ActivitiConstant.EXECUTOR_TYPE_b, sysUser.getId(), id, procInstId);
        //修改业务表的流程字段
        actBusinessService.updateBusinessStatus(actBusiness.getTableName(), actBusiness.getTableId(), "3");
        return Result.ok("操作成功");
    }


    // update-begin by wmf at 2022/3/31 9:11 for: 已结束流程回退到最后一个节点

    /**
     * 已结束流程回退到最后一个节点
     * @return
     * @throws ScriptException
     * @throws Exception
     */
    @AutoLog(value = "流程-已结束流程回退到最后一个节点")
    @ApiOperation(value = "流程-已结束流程回退", notes = "已结束流程回退")
    @RequestMapping(value = "/rollbackTask", method = RequestMethod.POST)
    public Result rollbackTask(@RequestBody ActZTask actZTask) throws ScriptException , Exception{

        if (StringUtils.isBlank(actZTask.getTaskId())){
            return Result.error("任务节点id不能为空！");
        }
        if (StringUtils.isBlank(actZTask.getProcInstId())){
            return Result.error("流程实例id不能为空！");
        }
        if (StringUtils.isBlank(actZTask.getProcessId())){
            return Result.error("所属流程d不能为空！");
        }
        if (StringUtils.isBlank(actZTask.getOwnerId())){
            return Result.error("审批人id不能为空！");
        }
        if (StringUtils.isBlank(actZTask.getTitle())){
            return Result.error("流程标题不能为空！");
        }
        if (StringUtils.isBlank(actZTask.getTableId())){
            return Result.error("tableid不能为空！");
        }
        if (actZTask.getState() == null || actZTask.getState().intValue() != 2){
            return Result.error("流程未结束，不能调用该方法！");
        }

        // 获取最后一个任务节点
        HistoricTaskInstance hisTask = historyService.createHistoricTaskInstanceQuery().taskId(actZTask.getTaskId()).singleResult();
        if (hisTask == null){
            return Result.error("未找到任务节点，请检查taksId是否正确：" + actZTask.getTaskId());
        }

        // 1、删除历史已办任务记录（根据taskid删除act_hi_taskinst表记录）
        actZTaskService.deleteHiTask(actZTask.getTaskId());
        // 2、把历史流程实例表(act_hi_procinst)的end_time设为空（流程图高亮标记用）
        actZTaskService.updateActHiProcInstEndtime(actZTask.getProcInstId());
        // 查询流程业务扩展表
        QueryWrapper<ActBusiness> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("table_id",actZTask.getTableId()).eq("proc_inst_id",actZTask.getProcInstId());
        queryWrapper.last(" limit 1");
        ActBusiness actBusiness = actBusinessService.getOne(queryWrapper);

        // 3、新增一条记录，运行时流程执行实例表，act_ru_execution,（因为流程结束了，当前运行实例表就没记录了，需要重新激活）
        Map<String, Object> actRuExecution = new HashMap<>();
        actRuExecution.put("id", hisTask.getExecutionId());
        actRuExecution.put("taskKey", hisTask.getTaskDefinitionKey());
        actRuExecution.put("procInstId", actZTask.getProcInstId());
        actRuExecution.put("processId", actZTask.getProcessId());
        actRuExecution.put("title", actZTask.getTitle());
        actRuExecution.put("busKey", actBusiness == null ? "" : actBusiness.getId());
        actZTaskService.insertActRuExecution(actRuExecution);

       String procInstId = hisTask.getProcessInstanceId();
       String procDefId = hisTask.getProcessDefinitionId();
       String backTaskKey = hisTask.getTaskDefinitionKey();

        // 取得流程定义
        ProcessDefinitionEntity definition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(procDefId);
        // 获取历史任务的Activity
        ActivityImpl hisActivity = definition.findActivity(backTaskKey);
        // 4、实现任务跳转到最后一节点
        managementService.executeCommand(new JumpTask(procInstId, hisActivity.getId()));

        // 5、删除待办表最后一个节点审批记录
        actZTaskService.delActZTaskByTaskIdProcInstId(actZTask.getProcInstId(),actZTask.getTaskId());

        // 6、重新分配原节点审批人
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procInstId).list();
        if (tasks != null && tasks.size() > 0) {
            tasks.forEach(e -> {
                for (String assignee : actZTask.getOwnerId().split(",")) {
                    taskService.addCandidateUser(e.getId(), assignee);
                    // 添加到扩展任务
                    ActZTask newZTask = new ActZTask();
                    BeanUtils.copyProperties(actZTask,newZTask);
                    newZTask.setId(null); // Id设为空表示新增
                    newZTask.setCreateTime(new Date()); // 创建时间
                    newZTask.setAuditTime(null);//审批时间
                    newZTask.setAuditComment(null);//审批意见
                    newZTask.setReceiveTime(actZTask.getCreateTime()); // 接收时间
                    newZTask.setNodeName(e.getName()); //任务节点名称
                    newZTask.setNodeState(0);//节点状态：0未处理1已处理
                    newZTask.setTaskId(e.getId()); //工作流任务id
                    newZTask.setState(1);//流程状态 0待提交 1审批中 2审批结束 3 驳回
                    actZTaskService.save(newZTask);
                }

            });
        }

        LoginUser fromUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        LoginUser toUser = sysBaseAPI.getUserById(actBusiness.getUserId());

        // 7、异步发消息，给流程发起人发一条消息
        actZprocessService.sendMessage(actBusiness.getId(), fromUser, toUser, ActivitiConstant.MESSAGE_PASS_CONTENT,
                String.format("您的 【%s】 流程已被重新激活，当前审批节点：" + actZTask.getNodeName(), actBusiness.getTitle()), false, false, false);

        // 异步发APP消息
        geTuiPushV2.pushToSingleByCid(toUser, ActivitiConstant.MESSAGE_PASS_CONTENT, String.format("您的 【%s】 流程已被重新激活，当前审批节点：" + actZTask.getNodeName(), actBusiness.getTitle()));

        // 8、记录实际审批人员
        actBusinessService.insertHI_IDENTITYLINK(IdUtil.simpleUUID(),
                ActivitiConstant.EXECUTOR_TYPE_b, fromUser.getId(), actZTask.getTaskId(), procInstId);

        return Result.OK();
    }
    // update-end by wmf at 2022/3/31 9:11 for: 已结束流程回退到最后一个节点

    /*提交申请 启动流程*/
    @AutoLog(value = "流程测试-启动流程")
    @ApiOperation(value = "流程测试-启动流程", notes = "流程测试-启动流程")
    @RequestMapping(value = "test/apply", method = RequestMethod.POST)
    public Result testApply(@ApiParam(value = "流程定义Id", required = true) String procDefId,
                        @ApiParam(value = "申请标题", required = true) String procDeTitle,
                        @ApiParam(value = "数据表主键", required = true) String tableId,
                        @ApiParam(value = "数据表名", required = true) String tableName,
                        @ApiParam(value = "启动类型-add-send", required = true) String sendType,
                        HttpServletRequest request) throws ScriptException , Exception{

        ActBusiness actBusiness = actBusinessService.getOne(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getTableId, tableId).last("limit 1"));
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String msg = "操作成功!";

        if (actBusiness == null) {

            // 等于空新发起， 新增数据 保存至我的申请业务
            actBusiness = new ActBusiness();
            actBusiness.setUserId(sysUser.getId());
            actBusiness.setTableId(tableId);
            actBusiness.setProcDefId(procDefId); // 设置流程定义Id
            actBusiness.setProcessKey("test"); // 设置流程标识
            actBusiness.setTitle(procDeTitle); // 设置流程标题
            actBusiness.setTableName(tableName);
            actBusinessService.save(actBusiness);
            actBusiness.setAssignees(sysUser.getId()); // 流程发起人，第一节点默认当前登录用户
            actBusiness.setRouteName("actZprocess"); // 设置表单路由
            // 启动一个新流程
            String processInstanceId = actZprocessService.startProcess(actBusiness);
            actBusiness.setProcInstId(processInstanceId);
            actBusiness.setStatus(ActivitiConstant.STATUS_DEALING);
            actBusiness.setResult(ActivitiConstant.RESULT_DEALING);
            actBusiness.setApplyTime(new Date());
            actBusinessService.updateById(actBusiness);

            if ("send".equals(sendType)){
                //修改业务表的流程字段
                actBusinessService.updateStatusAndProcInstId(actBusiness.getTableName(), actBusiness.getTableId(), "1", actBusiness.getProcInstId());
                // 流程提交到下一个节点
                this.pass(actBusiness.getTaskId(), processInstanceId, "", 0, "", true, false, false,false);
            }else {
                //修改业务表的流程字段
                actBusinessService.updateStatusAndProcInstId(actBusiness.getTableName(), actBusiness.getTableId(), "0", actBusiness.getProcInstId());
            }

        } else {
            // 保存之后发起
            if ("send".equals(sendType)){
                // 查询当前用户任务id
                List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(sysUser.getId()).processInstanceId(actBusiness.getProcInstId()).list();
                if (tasks.size() > 0) {
                    //修改业务表的流程字段
                    actBusinessService.updateStatusAndProcInstId(actBusiness.getTableName(), actBusiness.getTableId(), "1", actBusiness.getProcInstId());

                    // 流程提交到下一个节点
                    this.pass(tasks.get(0).getId(), actBusiness.getProcInstId(), "", 0, "", true, false, false,false);
                } else {
                    return Result.error("提交流程出错，未找到当前任务！");
                }
                msg = "流程发起成功！";
            }
        }

        return Result.ok(msg);
    }

}
